﻿/******************************************************************************
 * Name         : Exception.cpp
 * Author       : 671643387
 * Date         : 2015年9月23日
 * Description  :
 *****************************************************************************/

#include <errno.h>
#include <string.h>
#include <sstream>

#if defined(__LINUX__)
#include <execinfo.h>
#endif

#include "dev/base/Exception.hpp"
using namespace dev::base;

#define DEV_BACKTRACE 16

std::ostream& dev::base::operator << (std::ostream& os, dev::base::Exception& e)
{
    set_console_color(CONSOLE_COLOR_FOREGROUND_RED | CONSOLE_COLOR_FOREGROUND_INTENSITY);

    os << "exception at " << e.file() << "," << e.function() << "," << e.line() << std::endl;
    os << "code:        " << e.code() << std::endl;
    os << "error:       " << e.what() << std::endl;
    os << "stacktrace:  " << std::endl;
	os << e.stacktrace() << std::endl;

    set_console_color(CONSOLE_COLOR_FOREGROUND_WHITE);
    return os;
}

///////////////////////////////////////////////////////////////////////////////

Exception::Exception()
: code_(errno)
, error_(strerror(errno))
, stackstrace_("")
, file_(NULL)
, function_(NULL)
, line_(0)
{

}

Exception::Exception(int code)
: code_(code)
, error_("")
, stackstrace_("")
, file_(NULL)
, function_(NULL)
, line_(0)
{

}

Exception::Exception(const char * const error)
: code_(errno)
, error_(error)
, stackstrace_("")
, file_(NULL)
, function_(NULL)
, line_(0)
{

}

Exception::Exception(int code, const char * const error)
: code_(code)
, error_(error)
, stackstrace_("")
, file_(NULL)
, function_(NULL)
, line_(0)
{

}

Exception::Exception(const Exception& exception)
: code_(exception.code_)
, error_(exception.error_)
, stackstrace_(exception.stackstrace_)
, file_(exception.file_)
, function_(exception.function_)
, line_(exception.line_)
{

}

Exception::~Exception()
{

}

Exception& Exception::operator=(const Exception& exception)
{
    this->code_ = exception.code_;
    this->error_ = exception.error_;
    this->stackstrace_ = exception.stackstrace_;
    this->file_ = exception.file_;
    this->function_ = exception.function_;
    this->line_ = exception.line_;
    return *this;
}

void Exception::init(const char* file, const char* function, int line)
{
    file_ = file; function_ = function; line_ = line;

#if defined(__LINUX__)
    void* _ss_array[DEV_BACKTRACE] = { NULL };
    int _ss_stacks = backtrace(_ss_array, DEV_BACKTRACE); 
    char** _ss_stacktrace = backtrace_symbols(_ss_array, DEV_BACKTRACE); 
    for (int _ss_x = 0; _ss_x < _ss_stacks; ++_ss_x)
    {
        std::stringstream strs;
        std::string call_symb;
        strs << _ss_array[_ss_x];
        strs >> call_symb;
        stackstrace_.append("    called by ").append(call_symb).append("  ").append(_ss_stacktrace[_ss_x]).append("\n");
    }
    free(_ss_stacktrace);
#elif defined(__WINDOWS__)
    // TODO: 获取WINDOWS调用堆栈
#endif
}

#if defined(__WINDOWS__)
bool Exception::loadHelper()
{
    return true;
}
#endif
